#!/usr/bin/env jruby
# -*- coding: us-ascii -*-

# Need block arity (for sort_by) to be 1, BUT
# v1.6 says one-arg block is arity -1 (so is zero-arg block)  :-(
# Hence, must require RUBY_VERSION >= 1.8.
raise NotImplementedError, 'need version >= 1.8' if RUBY_VERSION < '1.8'

require 'md5'
dir = File.dirname(__FILE__)
require File.join(dir, '..', 'monkey', 'math')

########################################

class SortedStable
  include Enumerable
  
  def initialize(limit, sort_by_lambda)
    raise TypeError, 
      'limit must be Integer' unless limit.is_a? Integer
    raise RangeError, 
      'limit must be > 0' unless limit > 0
    raise ArgumentError, 
      'sort_by lambda not given' unless sort_by_lambda
    raise ArgumentError, 
      'lambda arity must be 1' unless sort_by_lambda.arity == 1
    
    @stable = Array.new
    @size_limit = limit
    @sort_by_lambda = sort_by_lambda  # just store for later use
    
  end
  
  attr_reader :size_limit
  
  def <<(obj)
    @stable << obj
    @stable = @stable.sort_by(&@sort_by_lambda).reverse
    @stable.pop if @stable.size > @size_limit
    self
  end
  
  def to_ary
    @stable
  end
  
  # delegate some stuff, but not all
  
  def [](index)
    @stable[index]
  end
  
  def include?(obj)
    @stable.include? obj
  end
  
  def size
    @stable.size
  end
  alias_method :length, :size
  
  def empty?
    @stable.empty?
  end
  
  def ==(other)
    @stable == other
  end
  
  def each
    @stable.each { |stallion| yield stallion }
  end
  
  def each_index
    @stable.each_index { |stallion, rank| yield stallion, rank }
  end
  
  def first
    @stable.first
  end
  
  def last
    @stable.last
  end
  
  def join(str)
    @stable.join str
  end
  
  def to_a
    @stable
  end
end

########################################

if $0 == __FILE__
  def r ; rand(100) ; end
  
  a = [r, r, r, r, r, r, r, r, r, r, r, r]
  p a.sort
  
  highest = SortedStable.new 5, lambda { |x| x }
  a.each { |n| highest << n }
  p highest
  
  lowest = SortedStable.new 5, lambda { |x| -x }
  a.each { |n| lowest << n }
  p lowest
end
